package com.extremelylargepackage.entity;

import java.io.IOException;
import java.util.Map;

import org.xml.sax.SAXException;

import com.extremelylargepackage.GameResources;
import com.extremelylargepackage.StatTracker;
import com.extremelylargepackage.sprite.AbstractSprite;
import com.extremelylargepackage.sprite.Animation;
import com.extremelylargepackage.sprite.AnimationParser;
import com.extremelylargepackage.sprite.MalformedAnimationException;

import android.graphics.Bitmap;
import android.graphics.Canvas;

public class Projectile extends Entity
{	
	public static final float MIN_Y_BOUNDS = (float)(-.25 * GameResources.SCREEN_HEIGHT);
	public static final float MAX_Y_BOUNDS = (float)(1.25 * GameResources.SCREEN_HEIGHT);
	public static final float MIN_X_BOUNDS = (float)(-.25 * GameResources.SCREEN_WIDTH);
	public static final float MAX_X_BOUNDS = (float)(1.25 * GameResources.SCREEN_WIDTH);
	
	/*** Persistent projectile info ***/

	protected Weapon _owner;
	protected float _damage;

	/**
	 * How many enemies this projectile can hit before dying
	 */
	protected int _pierceDepth;

	/*** Projectile state info ***/
	private int _hits;

	// To avoid piercing projectiles dealing damage each frame of collision.
	private Entity _lastCollidedEntity;

	protected Projectile()
	{
		super();
		_status = Status.alive;
		try 
		{
			_explosionAnim = AnimationParser.parseAnimation("projexp_1");
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}

	public void fire()
	{
		_locX = _owner._locX - (_sprite.getWidth() / 2);
		_locY = _owner._locY + (_owner._owner.getWidth()/2) - (_sprite.getHeight() / 2);
		_status = Status.alive;
		_hits = 0;
		_lastCollidedEntity = null;
		_dirX = 0;
		if(_owner._owner instanceof Player)
			_dirY = -1;
		else
			_dirY = 1;
		StatTracker.getInstance().RegisterShotFired(this.getName());
	}
	
	public void fire(float dx, float dy)
	{
		fire();
		_dirX = dx;
		_dirY = dy;
	}
	
	@Override
	public void updateState(long time) 
	{
		if(_status != Status.dead)
			updatePosition(time);
		
		if(_locY < MIN_Y_BOUNDS || _locY > MAX_Y_BOUNDS || _locX < MIN_X_BOUNDS || _locX > MAX_X_BOUNDS)
			_status = Status.dead;
		
		if(_status == Status.dying)
			onDying(time);
	}
	
	protected void updatePosition(long time)
	{
		//If the projectile is dying, keep the animation playing on the enemy relative to where it was hit.
		float tempSpeed = _speed;
		if(_status == Status.dying & _lastCollidedEntity != null)
		{
			tempSpeed = _lastCollidedEntity._speed;
			_dirX = _lastCollidedEntity._dirX;
			_dirY = _lastCollidedEntity._dirY;
		}
		
		if(_dirX != 0 || _dirY != 0)
		{
			float magnitude = (float)Math.sqrt((_dirX*_dirX) + (_dirY*_dirY));
			_dirY /= magnitude;
			_dirX /= magnitude;
			_locX += tempSpeed * _dirX * (time/1000f);
			_locY += tempSpeed * _dirY * (time/1000f);
		}
	}

	@Override
	public void onCollision(Entity z) 
	{	
		_hits++;
		_lastCollidedEntity = z;
		if(_hits >= _pierceDepth)
			setDying();
	}
	
	private void setDying()
	{
		_status = Status.dying;
		if(_explosionAnim != null)
		{
			_explosionAnim.start();
		}
	}

	@Override
	public void draw(Canvas c) 
	{
		if(_status == Status.alive)
			c.drawBitmap(_sprite.getBitmap(), _locX, _locY, null);
		if(_status == Status.dying && _explosionAnim != null && !_explosionAnim.finished())
			drawExplosion(c);
			
	}

	public float getDamage()
	{
		return _damage;
	}
	
	@Override
	public Object clone()
	{
		//TODO: super.clone()
		Projectile copy = new Projectile();
		copy._damage = _damage;
		copy._name = _name;
		copy._speed = _speed;
		copy._sprite = _sprite;
		copy._pierceDepth = _pierceDepth;
		copy._explosionAnim = (Animation) _explosionAnim.clone();
		return copy;
	}

	@Override
	public Map<String, Object> getState()
	{
		Map<String, Object> res = super.getState();

		res.put("hits", String.valueOf(_hits));
		// TODO -- last collided entity. not strictly necessary, but open to exploitation
		//private Entity _lastCollidedEntity;

		return res;
	}
}
